Passed
Push — main ( 21e4bd...1e2ac3 )
by Dylan
04:28
created

Polyrat.evaluate   B

Complexity

Conditions 6

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 10
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 6
rs 8.6666
c 0
b 0
f 0
1 2
import {Rat} from './Rat'
2 2
import Symbolizer from './Symbolizer'
3
4
export interface Coefficents {
5
  [Key: string]: Rat;
6
}
7
8
/**
9
 * @class Rational polynumber
10
 * @name Polyrat
11
 */
12 2
export class Polyrat {
13
14
  // coefficent values are indexed with their the exponents in each dimension, comma-separated, as the key
15 21
  coefficents: Coefficents = {}
16
17
  // the dimension is how many params there are, defined by the length of the exponent keys
18 21
  dimension = 0
19
20
  // unique symbols for each dimension
21 21
  symbols = ''
22
23
  /**
24
   * Initialize a rational polynumber.
25
   */
26
  constructor(coefficents?: Coefficents) {
27 21
    if (coefficents) {
28 19
      this.coefficents = coefficents
29
    }
30 21
    if (Object.keys(this.coefficents).length) {
31 14
      this.dimension = Object.keys(this.coefficents)[0].split(',').length
32
    }
33 21
    const sg = (new Symbolizer('xyzw')).generator()
34 21
    for (let i=0; i<this.dimension; i++) {
35 21
      this.symbols += sg.next().value
36
    }
37
  }
38
39
  /**
40
   * Evaluate the result given the parameters for each dimension.
41
   */
42
  evaluate(parameters: Rat[]): Rat {
43 1
    let result: Rat = new Rat()
44 1
    for (const [exponents, coefficent] of Object.entries(this.coefficents)) {
45 1
      let value: Rat = coefficent
46 1
      const dimensions = exponents.split(',')
47 1
      for (let i=0; i<dimensions.length; i++) {
48 1
        value = value.mul(parameters[i].pow(new Rat(parseInt(dimensions[i], 10))))
49
      }
50 1
      result = result.add(value)
51
    }
52 1
    return result
53
  }
54
55
  /**
56
   * The text representation.
57
   */
58
  toString(): string {
59 2
    return `${this.constructor.name}(${this.toJSON()})`
60
  }
61
62
  /**
63
   * The JSON representation.
64
   */
65
  toJSON(): string {
66
    // return JSON.stringify(this.coefficents)
67 3
    const r = []
68 3
    for (const [exponents, coefficent] of Object.entries(this.coefficents)) {
69 7
      r.push(`'${exponents}':'${coefficent.toString()}'`)
70
    }
71 3
    return `[${r.join(',')}]`
72
  }
73
74
  /**
75
   * The formula in the human way with exponents as HTML sups.
76
   */
77
  toHTMLFormula(): string {
78 5
    const r: string[] = []
79 5
    for (const [exponents, coefficent] of Object.entries(this.coefficents)) {
80 12
      const t: string[] = []
81 12
      const f = coefficent.toString()
82 12
      if (f !== '1') t.push(f)
83 12
      const dimensions = exponents.split(',')
84 12
      for (let i=0; i<dimensions.length; i++) {
85 24
        if (dimensions[i] !== '0') {
86 12
          if (dimensions[i] === '1') {
87 3
            t.push(this.symbols[i])
88
          }
89
          else {
90 9
            t.push(`${this.symbols[i]}<sup>${parseInt(dimensions[i], 10)}</sup>`)
91
          }
92
        }
93
      }
94 12
      if (t) r.push(t.join(''))
95
    }
96 5
    if (r.length === 0) return '0'
97 4
    return r.join(' + ')
98
  }
99
100
  /**
101
   * The formula in the standard alpha form as HTML.
102
   */
103
  toStandardAlphaFormHTML(): string {
104 7
    const rn: string[] = []
105 7
    const rd: string[] = []
106 7
    if (!Object.keys(this.coefficents).length) return '0'
107 6
    for (const [exponents, coefficent] of Object.entries(this.coefficents)) {
108 9
      const tn: string[] = []
109 9
      const td: string[] = []
110 9
      const f = coefficent.toString()
111 9
      if (f !== '1') tn.push(f)
112 9
      const dimensions = exponents.split(',')
113 9
      for (let i=0; i<dimensions.length; i++) {
114 15
        if (dimensions[i] !== '0') {
115 8
          if (dimensions[i] === '1') {
116 4
            tn.push(this.symbols[i])
117
          }
118
          else {
119 4
            const exponent = parseInt(dimensions[i], 10)
120 4
            if (exponent > 0) {
121 1
              tn.push(`${this.symbols[i]}<sup>${exponent}</sup>`)
122
            }
123
            else {
124 3
              if (exponent === -1) {
125 2
                td.push(this.symbols[i])
126
              }
127
              else {
128 1
                td.push(`${this.symbols[i]}<sup>${-exponent}</sup>`)
129
              }
130
            }
131
          }
132
        }
133
      }
134 9
      if (tn.length) rn.push(tn.join(''))
135 9
      if (td.length) rd.push(td.join(''))
136
    }
137 6
    if (rn.length === 0) return '1'
138 4
    if (rd.length === 0) return rn.join(' + ')
139 2
    return rn.join(' + ') + ' / ' + rd.join(' + ')
140
  }
141
  
142
  /**
143
   * The "calc" code for evaluating the value.
144
   */
145
  toCalcFormula(): string {
146 5
    const r: string[] = []
147 5
    for (const [exponents, coefficent] of Object.entries(this.coefficents)) {
148 11
      const t: string[] = []
149 11
      const f = coefficent.toString()
150 11
      if (f !== '1') t.push(f)
151 11
      const dimensions = exponents.split(',')
152 11
      for (let i=0; i<dimensions.length; i++) {
153 20
        if (dimensions[i] !== '0') {
154 11
          if (dimensions[i] === '1') {
155 4
            t.push(this.symbols[i])
156
          }
157
          else {
158 7
            t.push(`${this.symbols[i]}^${parseInt(dimensions[i], 10)}`)
159
          }
160
        }
161
      }
162 11
      if (t.length) r.push(t.join('*'))
163
    }
164 5
    if (r.length === 0) return '0'
165 4
    return r.join(' + ')
166
  }
167
168
  /**
169
   * The GLSL code for evaluating the value.
170
   */
171
  toGLSLFormula(): string {
172 3
    const r: string[] = []
173 3
    for (const [exponents, coefficent] of Object.entries(this.coefficents)) {
174 7
      const t: string[] = []
175 7
      const f = coefficent.toString()
176 7
      if (f !== '1') t.push(f+'.0')
177 7
      const dimensions = exponents.split(',')
178 7
      for (let i=0; i<dimensions.length; i++) {
179 14
        if (dimensions[i] !== '0') {
180 8
          let exponent = parseInt(dimensions[i], 10)
181 8
          const recipricol = exponent < 0
182
          // pow doesn't work for < 0
183
          // t.push(`pow(${this.symbols[i]},${exponent}.0)`)
184
          // muliply instead
185 8
          if (recipricol) {
186 1
            t.push('1.0/(1.0')
187 1
            exponent = -exponent
188
          }
189 8
          t.push(this.symbols[i].repeat(exponent).split('').join('*'))
190 8
          if (recipricol) {
191 1
            t.push('1.0)')
192 1
            exponent = -exponent
193
          }
194
        }
195
      }
196 7
      if (t.length) r.push(t.join('*'))
197
    }
198 3
    if (r.length === 0) return '0.0'
199 2
    return r.join('+')
200
  }
201
202
  /**
203
   * Clone this.
204
   */
205
  clone(): Polyrat {
206 1
    return new Polyrat(this.coefficents)
207
  }
208
209
}
210
211
/**
212
 * Parse the string and return it as a Polyrat.
213
 */
214 2
export const stringToPolyrat = (s: string): Polyrat => {
215 1
  return new Polyrat(JSON.parse(s) as Coefficents)
216
}
217
218
export default Polyrat
219